package com.xiaoyun.xpath.handler.field;


import cn.wanghaomiao.xpath.model.JXDocument;
import com.xiaoyun.xpath.HandlerUtils;
import com.xiaoyun.xpath.handler.annotation.Xpath;

import java.lang.reflect.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class ListFieldHandler<T> extends StringFieldHandler<T> {


    @Override
    public void handlerField(Class<T> clazz, JXDocument jxDocument, T t, Map<String, String> mappingMap, Field field) throws Exception {
        String fieldName = field.getName();

        Type genericType = field.getGenericType();
        if (genericType instanceof ParameterizedType) {
            String typeName = getTypeName((ParameterizedType) genericType);
            Class<?> clazzItem = Class.forName(typeName);
            Xpath xpathList = field.getAnnotation(Xpath.class);
            String sonUrl = xpathList.sonName();
            List<Object> listObj = new ArrayList<>();
            if (HandlerUtils.isNotNullMap(mappingMap) && mappingMap.get(fieldName) != null) {
                String xpathMapping = mappingMap.get(fieldName);
                listMethodInvoke(clazz, jxDocument, t, fieldName, clazzItem, sonUrl, listObj, xpathMapping);
            } else {
                Xpath xpath = field.getAnnotation(Xpath.class);
                if (xpath != null) {
                    String xpathMapping = xpath.pattern();
                    listMethodInvoke(clazz, jxDocument, t, fieldName, clazzItem, sonUrl, listObj, xpathMapping);
                }
            }
        } else {
            //当list没有参数类型
            super.handlerField(clazz, jxDocument, t, mappingMap, field);
        }


    }

    protected String getTypeName(ParameterizedType genericType) {
        Type[] types = genericType.getActualTypeArguments();
        return types[0].getTypeName();
    }

    @Override
    protected <T> void stringMethodInvoke(Class<T> clazz, JXDocument jxDocument, T t, String fieldName, String xpathMapping) throws Exception {
        List<Object> list = jxDocument.sel(xpathMapping);

        String methodName = HandlerUtils.getMethodName(fieldName);
        Method method = clazz.getDeclaredMethod(methodName, List.class);
        method.setAccessible(true);
        method.invoke(t, list);
    }

    protected <T> void listMethodInvoke(Class<T> clazz, JXDocument jxDocument, T t, String fieldName, Class<?> clazzItem, String sonUrl, List<Object> listObj, String xpathMapping) throws Exception {
        List<Object> list = jxDocument.sel(xpathMapping);
        String methodNameUrl = HandlerUtils.getMethodName(sonUrl);
        Method methodUrl = clazzItem.getDeclaredMethod(methodNameUrl, String.class);
        for (Object o : list) {
            String str = o.toString();
            Object obj = clazzItem.getDeclaredConstructor().newInstance();
            methodUrl.setAccessible(true);
            methodUrl.invoke(obj, str);
            listObj.add(obj);
        }
        String methodName = HandlerUtils.getMethodName(fieldName);
        Method method = clazz.getDeclaredMethod(methodName, List.class);
        method.setAccessible(true);
        method.invoke(t, listObj);
    }

    @Override
    public String getType() {
        return List.class.getName();
    }


}
